/**
 * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 */

package com.iwindplus.gateway.server.service.impl;

import cn.hutool.core.text.CharSequenceUtil;
import com.iwindplus.boot.util.JacksonUtil;
import com.iwindplus.gateway.server.domain.constant.GatewayConstant.RouteConstant;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * redis路由定义存储器.
 *
 * @author zengdegui
 * @since 2020/4/15
 */
@Slf4j
@RefreshScope
@ConditionalOnProperty(prefix = "gateway.route", name = "write-redis", havingValue = "true")
@Component
public class RedisRouteDefinitionRepositoryImpl implements RouteDefinitionRepository {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitions = this.redisTemplate.opsForHash().values(RouteConstant.ROUTE_KEY).stream()
            .map(routeDefinition -> JacksonUtil.parseObject(routeDefinition.toString(), RouteDefinition.class))
            .collect(Collectors.toCollection(ArrayList::new));
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(routeDefinition -> {
            String json = JacksonUtil.toJsonStr(routeDefinition);
            if (CharSequenceUtil.isNotBlank(json)) {
                this.redisTemplate.opsForHash().put(RouteConstant.ROUTE_KEY, routeDefinition.getId(), json);
            }
            return Mono.empty();
        });

    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            Boolean hasKey = this.redisTemplate.opsForHash().hasKey(RouteConstant.ROUTE_KEY, id);
            if (Boolean.TRUE.equals(hasKey)) {
                this.redisTemplate.opsForHash().delete(RouteConstant.ROUTE_KEY, id);
                return Mono.empty();
            }
            return Mono.error(new NotFoundException("Routing info not found: " + routeId));
        });
    }
}
